Skip to content

Conversation

@yangxk1
Copy link
Contributor

@yangxk1 yangxk1 commented Sep 29, 2025

Reason for this PR

close #778

What changes are included in this PR?

Are these changes tested?

Are there any user-facing changes?

@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 70.96774% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.68%. Comparing base (6f112c6) to head (2f66dde).

Files with missing lines Patch % Lines
...java/org/apache/graphar/info/type/Cardinality.java 62.50% 3 Missing and 3 partials ⚠️
.../apache/graphar/info/saver/BaseGraphInfoSaver.java 37.50% 3 Missing and 2 partials ⚠️
...rc/main/java/org/apache/graphar/info/EdgeInfo.java 50.00% 1 Missing and 1 partial ⚠️
...ava/org/apache/graphar/info/yaml/PropertyYaml.java 75.00% 1 Missing and 1 partial ⚠️
.../java/org/apache/graphar/info/yaml/VertexYaml.java 66.66% 1 Missing and 1 partial ⚠️
...rc/main/java/org/apache/graphar/info/Property.java 90.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #780      +/-   ##
============================================
+ Coverage     76.59%   76.68%   +0.08%     
- Complexity      560      583      +23     
============================================
  Files            83       84       +1     
  Lines          8679     8736      +57     
  Branches       1006     1012       +6     
============================================
+ Hits           6648     6699      +51     
- Misses         1813     1814       +1     
- Partials        218      223       +5     
Flag Coverage Δ
java-info 83.09% <70.96%> (+0.34%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@yangxk1 yangxk1 requested a review from Thespica September 29, 2025 07:16
@yangxk1
Copy link
Contributor Author

yangxk1 commented Oct 9, 2025

Hey @Thespica, please help me review.

@yangxk1 yangxk1 requested a review from Copilot November 25, 2025 03:27
Copilot finished reviewing on behalf of yangxk1 November 25, 2025 03:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for multi-valued properties (LIST and SET cardinality) in GraphAr's Java implementation, enabling properties to hold multiple values instead of just single values. The implementation introduces a new Cardinality enum and integrates it throughout the info layer for YAML serialization/deserialization.

Key Changes

  • Introduces Cardinality enum (SINGLE, LIST, SET) to distinguish single-valued from multi-valued properties
  • Updates Property, PropertyYaml, and related info classes to support cardinality metadata
  • Adds validation rules: edges only support SINGLE cardinality, and CSV files don't support multi-cardinality properties
  • Enhances BaseGraphInfoSaver to auto-generate filenames when saving to directories

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
maven-projects/info/src/main/java/org/apache/graphar/info/type/Cardinality.java New enum defining SINGLE, LIST, and SET cardinality types with string conversion methods
maven-projects/info/src/main/java/org/apache/graphar/info/Property.java Adds cardinality field and constructors to support multi-valued properties
maven-projects/info/src/main/java/org/apache/graphar/info/yaml/PropertyYaml.java Adds cardinality field for YAML serialization, with special handling to omit SINGLE from output
maven-projects/info/src/main/java/org/apache/graphar/info/PropertyGroup.java Adds getCardinality() method and validation to reject multi-cardinality in CSV files
maven-projects/info/src/main/java/org/apache/graphar/info/VertexInfo.java Exposes getCardinality() method and adds validation calls before dumping
maven-projects/info/src/main/java/org/apache/graphar/info/EdgeInfo.java Adds validation to reject multi-cardinality properties in edges and validation calls before dumping
maven-projects/info/src/main/java/org/apache/graphar/info/GraphInfo.java Adds validation calls before dumping YAML
maven-projects/info/src/main/java/org/apache/graphar/info/yaml/VertexYaml.java Adds unused labels field (unrelated to multi-property feature)
maven-projects/info/src/main/java/org/apache/graphar/info/saver/BaseGraphInfoSaver.java Adds auto-filename generation when URIs are directories
maven-projects/info/src/test/java/org/apache/graphar/info/MultiPropertyTest.java Comprehensive test suite for cardinality functionality including YAML round-trip and validation
maven-projects/info/src/test/java/org/apache/graphar/info/TestDataFactory.java Adds factory method for creating properties with cardinality
maven-projects/info/src/test/java/org/apache/graphar/info/TestUtil.java Adds helper methods to access LDBC test data with multi-property support
maven-projects/info/src/test/java/org/apache/graphar/info/TestVerificationUtils.java Adds cardinality assertion to property comparison
maven-projects/info/src/test/java/org/apache/graphar/info/GraphInfoTest.java Adds cardinality assertions to existing property tests

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +132 to +139
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
VertexYaml vertexYaml = new VertexYaml(this);
yaml.dump(vertexYaml, output);
}

public String dump() {
isValidated();
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to isValidated() doesn't use its return value. If the intent is to validate before dumping, this should either throw an exception when validation fails, or check the return value and throw an appropriate exception. As written, invalid VertexInfo objects can still be dumped to YAML.

Suggested change
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
VertexYaml vertexYaml = new VertexYaml(this);
yaml.dump(vertexYaml, output);
}
public String dump() {
isValidated();
if (!isValidated()) {
throw new IllegalStateException("VertexInfo object is not valid and cannot be dumped.");
}
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
VertexYaml vertexYaml = new VertexYaml(this);
yaml.dump(vertexYaml, output);
}
public String dump() {
if (!isValidated()) {
throw new IllegalStateException("VertexInfo object is not valid and cannot be dumped.");
}

Copilot uses AI. Check for mistakes.
PropertyYaml invalidYaml = new PropertyYaml();
invalidYaml.setName("invalid_prop");
invalidYaml.setData_type("string");
invalidYaml.setCardinality("INVALID"); // This should default to SINGLE
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "This should default to SINGLE" but the test correctly expects an IllegalArgumentException to be thrown. The comment is misleading and should be updated to reflect that invalid cardinality values should throw an exception rather than defaulting to SINGLE.

Suggested change
invalidYaml.setCardinality("INVALID"); // This should default to SINGLE
invalidYaml.setCardinality("INVALID"); // This should throw an IllegalArgumentException

Copilot uses AI. Check for mistakes.
Comment on lines +131 to +145
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
yaml.dump(graphYaml, output);
}

public String dump(URI storeUri) {
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
return yaml.dump(graphYaml);
}

public String dump() {
isValidated();
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to isValidated() doesn't use its return value. If the intent is to validate before dumping, this should either throw an exception when validation fails, or check the return value and throw an appropriate exception. As written, invalid GraphInfo objects can still be dumped to YAML.

Suggested change
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
yaml.dump(graphYaml, output);
}
public String dump(URI storeUri) {
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
return yaml.dump(graphYaml);
}
public String dump() {
isValidated();
if (!isValidated()) {
throw new IllegalStateException("GraphInfo is not valid and cannot be dumped.");
}
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
yaml.dump(graphYaml, output);
}
public String dump(URI storeUri) {
if (!isValidated()) {
throw new IllegalStateException("GraphInfo is not valid and cannot be dumped.");
}
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
return yaml.dump(graphYaml);
}
public String dump() {
if (!isValidated()) {
throw new IllegalStateException("GraphInfo is not valid and cannot be dumped.");
}

Copilot uses AI. Check for mistakes.
Comment on lines +500 to +507
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
EdgeYaml edgeYaml = new EdgeYaml(this);
yaml.dump(edgeYaml, output);
}

public String dump() {
isValidated();
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to isValidated() doesn't use its return value. If the intent is to validate before dumping, this should either throw an exception when validation fails, or check the return value and throw an appropriate exception. As written, invalid EdgeInfo objects can still be dumped to YAML.

Suggested change
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
EdgeYaml edgeYaml = new EdgeYaml(this);
yaml.dump(edgeYaml, output);
}
public String dump() {
isValidated();
if (!isValidated()) {
throw new IllegalStateException("EdgeInfo object is not valid and cannot be dumped.");
}
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
EdgeYaml edgeYaml = new EdgeYaml(this);
yaml.dump(edgeYaml, output);
}
public String dump() {
if (!isValidated()) {
throw new IllegalStateException("EdgeInfo object is not valid and cannot be dumped.");
}

Copilot uses AI. Check for mistakes.
this.data_type = "";
this.is_primary = false;
this.is_nullable = Optional.empty();
this.cardinality = "single"; // Default to single
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting a default value of "single" for the cardinality field in the no-arg constructor is problematic. When YAML deserialization occurs and no cardinality field is present, the field will remain as the default "single". However, the getCardinality() method (line 89) returns null for "single" cardinality to avoid serializing it. This creates an inconsistency. Consider initializing cardinality to null instead, and handle the default in the Property constructor that takes PropertyYaml.

Suggested change
this.cardinality = "single"; // Default to single
this.cardinality = null; // No default; handle in Property constructor

Copilot uses AI. Check for mistakes.
Comment on lines +131 to +145
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
yaml.dump(graphYaml, output);
}

public String dump(URI storeUri) {
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
return yaml.dump(graphYaml);
}

public String dump() {
isValidated();
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to isValidated() doesn't use its return value. If the intent is to validate before dumping, this should either throw an exception when validation fails, or check the return value and throw an appropriate exception. As written, invalid GraphInfo objects can still be dumped to YAML.

Suggested change
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
yaml.dump(graphYaml, output);
}
public String dump(URI storeUri) {
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
return yaml.dump(graphYaml);
}
public String dump() {
isValidated();
if (!isValidated()) {
throw new IllegalStateException("GraphInfo is not valid and cannot be dumped.");
}
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
yaml.dump(graphYaml, output);
}
public String dump(URI storeUri) {
if (!isValidated()) {
throw new IllegalStateException("GraphInfo is not valid and cannot be dumped.");
}
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
return yaml.dump(graphYaml);
}
public String dump() {
if (!isValidated()) {
throw new IllegalStateException("GraphInfo is not valid and cannot be dumped.");
}

Copilot uses AI. Check for mistakes.
Comment on lines +131 to +145
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
yaml.dump(graphYaml, output);
}

public String dump(URI storeUri) {
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
return yaml.dump(graphYaml);
}

public String dump() {
isValidated();
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to isValidated() doesn't use its return value. If the intent is to validate before dumping, this should either throw an exception when validation fails, or check the return value and throw an appropriate exception. As written, invalid GraphInfo objects can still be dumped to YAML.

Suggested change
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
yaml.dump(graphYaml, output);
}
public String dump(URI storeUri) {
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
return yaml.dump(graphYaml);
}
public String dump() {
isValidated();
if (!isValidated()) {
throw new IllegalStateException("GraphInfo is not valid and cannot be dumped.");
}
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
yaml.dump(graphYaml, output);
}
public String dump(URI storeUri) {
if (!isValidated()) {
throw new IllegalStateException("GraphInfo is not valid and cannot be dumped.");
}
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
GraphYaml graphYaml = new GraphYaml(storeUri, this);
return yaml.dump(graphYaml);
}
public String dump() {
if (!isValidated()) {
throw new IllegalStateException("GraphInfo is not valid and cannot be dumped.");
}

Copilot uses AI. Check for mistakes.
Comment on lines +632 to +635
if (p.getCardinality() != Cardinality.SINGLE) {
// edge property only supports single cardinality
return false;
}
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] EdgeInfo doesn't expose a getCardinality(String propertyName) method like VertexInfo does (line 89 in VertexInfo.java). For API consistency, consider adding this method to EdgeInfo as well, which would always return Cardinality.SINGLE for valid edge properties. This would provide a uniform API across both VertexInfo and EdgeInfo.

Copilot uses AI. Check for mistakes.
Comment on lines +500 to +507
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
EdgeYaml edgeYaml = new EdgeYaml(this);
yaml.dump(edgeYaml, output);
}

public String dump() {
isValidated();
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The call to isValidated() doesn't use its return value. If the intent is to validate before dumping, this should either throw an exception when validation fails, or check the return value and throw an appropriate exception. As written, invalid EdgeInfo objects can still be dumped to YAML.

Suggested change
isValidated();
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
EdgeYaml edgeYaml = new EdgeYaml(this);
yaml.dump(edgeYaml, output);
}
public String dump() {
isValidated();
if (!isValidated()) {
throw new IllegalStateException("EdgeInfo object is not valid and cannot be dumped.");
}
Yaml yaml = new Yaml(GraphYaml.getRepresenter(), GraphYaml.getDumperOptions());
EdgeYaml edgeYaml = new EdgeYaml(this);
yaml.dump(edgeYaml, output);
}
public String dump() {
if (!isValidated()) {
throw new IllegalStateException("EdgeInfo object is not valid and cannot be dumped.");
}

Copilot uses AI. Check for mistakes.
LIST,
/** Set of values property (no duplicates) */
SET;

Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method overrides Enum.toString; it is advisable to add an Override annotation.

Suggested change
@Override

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(java,info): support multi-property in yaml #768

2 participants